﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


//    * 使用基本的BitMatrix
//    * 使用8bit byte存储
//    * 对每种可能的byte值建立static bias array：

//0: [9]*
//1: [8]
//2: [7]
//3: [7,8]
//4: [6]
//5: [6,8]
//...
//255: [1,2,3,4,5,6,7,8]

//    * 尽可能快地读取给定Index的相关Indexes



namespace GenericLibrary.Common.X {

    public class RelationalMatrix {

        private static List<int>[] _byte2Indexes;

        static RelationalMatrix() {

            _byte2Indexes = new List<int>[byte.MaxValue - byte.MinValue + 1];

            for(byte i = byte.MinValue; true; i++) {
                _byte2Indexes[i] = new List<int>();
                for(int j = 0; j < 8; j++) {
                    if((i & (0x01 << j)) != 0) {
                        _byte2Indexes[i].Add(j);
                    }
                }
                if(i == byte.MaxValue) {
                    break;
                }
            }
        }

        private byte[,] _bitMap;

        public RelationalMatrix(int sourceSize, int targetSize) {
            this._bitMap = new byte[sourceSize, (int)Math.Ceiling(targetSize / 8d)];
        }

        public int SourceSize {
            get {
                return this._bitMap.GetLength(0);
            }
        }

        public int TargetSize {
            get {
                return this._bitMap.GetLength(1) * 8;
            }
        }

        public bool this[int sourceIndex, int targetIndex] {
            set {
                if(value) {
                    this._bitMap[sourceIndex, targetIndex / 8] |= (byte)(0x01 << (targetIndex % 8));
                } else {
                    this._bitMap[sourceIndex, targetIndex / 8] &= (byte)(~(0x01 << (targetIndex % 8)));
                }
            }
            get {
                return (this._bitMap[sourceIndex, targetIndex / 8] & (0x01 << (targetIndex % 8))) != 0;
            }
        }

        public IEnumerable<int> GetSourceIndexes(int targetIndex) {

            int targetByteIndex = targetIndex / 8;
            int targetBitIndex = targetIndex % 8;
            for(int sourceIndex = 0; sourceIndex < this._bitMap.GetLength(0); sourceIndex++) {
                if((this._bitMap[sourceIndex, targetByteIndex] & (0x01 << targetBitIndex)) != 0) {
                    yield return sourceIndex;
                }
            }
        }

        public IEnumerable<int> GetTargetIndexes(int sourceIndex) {

            for(int targetByteIndex = 0; targetByteIndex < this._bitMap.GetLength(1); targetByteIndex++) {
                int targetIndexOffset = targetByteIndex * 8;
                foreach(int targetBitIndex in _byte2Indexes[this._bitMap[sourceIndex, targetByteIndex]]) {
                    yield return targetIndexOffset + targetBitIndex;
                }
            }
        }

    }
}
